#ifndef CACULATOR_H
#define CACULATOR_H

#include <iostream>
#include <cmath>

//定义最大数组长度
#define StrExtFloat_flen 1024
//定义最大字符串长度
#define StrExtFloat_slen 1024

template<typename DT>
class ArrayStack
{
 public:
  ArrayStack()
  {
    count = 0;
  }
  
  ~ArrayStack()
  {}
 
 public:
  DT top()            //获取栈顶元素
  {
    if ( count != 0 )
      {
	return array[count - 1];
      }
  };
  
  void push( DT t )        //压栈操作
  {
    if ( count != capacity )    //先判断是否栈满
      {
	array[count++] = t;   
      }
  };
  
  DT pop()            //弹栈操作
  {
    if ( count != 0 )    //先判断是否是空栈
      {
	return array[--count];
      }
  };
  
  bool isEmpty()        //判空操作
  {
    return count == 0; //栈元素为0时为栈空
  };
  
  int size()            //求栈的大小
  {
    return count;
  };
 
 private:
  int count;            //栈的元素数量
  int capacity = StrExtFloat_flen;        //栈的容量
  DT array[StrExtFloat_flen];            //底层为数组
};

struct Operator
{
  int priority;
  char operat;
};

int flag = 0; //用作异常处理和判断是否读到运算符

void StrExtFloat( double* num, char* Str, char* str )
{
  //遍历深度
  int Fflag = 0;
  //数字个数
  int Fnum = 0;
  //用于浮点数识别
  char num_start = 0, num_point = 0;
  //字符串栈
  ArrayStack<Operator> stack;
  Operator ope[StrExtFloat_slen];
  int num1 = 0;
  //遍历到字符串尾部
  while ( *Str != '\0' )
    {	
      Fflag++;
      //防止查询超过边界
      if( Fflag > StrExtFloat_slen )
	break;
      //判断是不是数字
      if( *Str >= '0' && *Str <= '9' )
	{
	  //printf("%c",*Str);
	  //判断数字存在
	  num_start = 1;
	  //判断是否存在小数点
	  if( num_point >= 1 )
	    {
	      num_point++;
	      //当前小数部分的数值
	      double fpoint = *Str - '0';
	      for( int i = 1; i<num_point; i++ )
		{
		  fpoint = fpoint/10.;
		}
	      //加入小数部分
	      num[Fnum+1] = num[Fnum+1] + fpoint;
	    }
	  else
	    {
	      //加入整数部分
	      num[Fnum+1] = num[Fnum+1]*10+(*Str - '0');
	    }
	}
      else if( *Str == '.' ) //判断为小数点
	{
	  if( num_point >= 1 )
	    {
	      flag = 30;
	      break;
	    }
	  if( num_start==1 )//发现存在小数点
	    {
	      num_point=1;
	    }
	}
      else //判断为其他字符
	{
	  if ( num_start == 1 )
	    {
	      Fnum++;//统计个数加一
	    }
	  //清空字符统计与小数点统计
	  num_start = 0;
	  num_point = 0;
	}

      //判断是不是运算符，如果是运算符则flag变为1
      if ( *Str == '+' )
	{
	  ope[num1].priority = 1;
	  ope[num1].operat = '+';
	  flag = 1;
	}
      else if ( *Str == '-' )
	{
	  ope[num1].priority = 1;
	  ope[num1].operat = '-';
	  flag = 1;
	}
      else if ( *Str == '*' )
	{
	  ope[num1].priority = 2;
	  ope[num1].operat = '*';
	  flag = 1;
	}
      else if ( *Str == '/' )
	{
	  ope[num1].priority = 2;
	  ope[num1].operat = '/';
	  flag = 1;
	}
      else if ( *Str == '^' )
	{
	  ope[num1].priority = 3;
	  ope[num1].operat = '^';
	  flag = 1;
	}
      else if ( *Str == '(' )
	{
	  ope[num1].priority = 4;
	  ope[num1].operat = '(';
	  flag = 1;
	}
      else if ( *Str == ')' )
	{
	  ope[num1].priority = 4;
	  ope[num1].operat = ')';
	  flag = 1;
	}
      if ( flag == 1 )
	{
	  //如果当前栈为空，或者栈顶运算符优先级低于当前运算符，或者栈顶运算符是‘（’则入栈
	  if ( stack.isEmpty() || stack.top().priority < ope[num1].priority || stack.top().operat == '(' )
	    stack.push(ope[num1]);
	  //如果栈顶运算符优先级大于等于当前运算符，则弹出至str中，重复此操作
	  else
	    {
	      while ( stack.top().priority >= ope[num1].priority && stack.top().operat != '(' )
	        { str[Fnum+1] = stack.pop().operat; Fnum++; }
	      stack.push(ope[num1]);
	    }
	  //如果栈顶运算符是‘）’，则不断弹出至‘（’
	  if ( stack.top().operat == ')' )
	    {
	      ope[999] = stack.pop();
	      while ( stack.top().operat != '(' && !stack.isEmpty() )
		{ str[Fnum+1] = stack.pop().operat; Fnum++; }
	      //如果到栈为空栈都没有找到对应的‘（’则触发异常处理
	      if ( stack.isEmpty() ) { std::cout << "错误：括号不匹配" << std::endl; flag = -1; break;}
	      else ope[999] = stack.pop();
	    }
	  num1++;
	  flag = 0;
	}
      
      //指针移动
      *(Str++);
    }
  //如果不是以字符结尾
  if ( num_start == 1 )
    {
      Fnum++;//统计个数加一
    }
  //为了弹出栈內的所有运算符
  while ( !stack.isEmpty() )
    {
      str[Fnum+1] = stack.pop().operat;
      Fnum++;
      if ( str[Fnum] == '(' )
	{ std::cout << "错误：括号不匹配" << std::endl; flag = -1; break; }
    }
  //放入提取到的数字个数
  num[0] = Fnum;
  //如果触发异常处理，则清空当前存储内容
  if ( flag == -1 || flag == 30 )
    {
      for ( int i = 1; i <=num[0]; i++ )
	{ num[i] = 0.00; str[i] = '\0'; }
      num[0] = 0;
    }
  
};

void caculator( double* num, char* Str, char* str )
{
  //用于计算的数字栈
  ArrayStack<float> stack;
  //用于存放栈顶元素和计算结果
  double result, a, b;
  if ( flag != -1 )
    {
      for ( int i = 1; i <= num[0]; i++ )
	{
	  //如果str[i]为零，则将num[i]入栈
	  if ( str[i] == '\0' )
	    {
	      stack.push( num[i] );
	    }
	  //当str[i]不为零时，弹出栈顶两元素进行相应计算后将结果入栈
	  else if ( str[i] == '+' )
	    {
	      if ( !stack.isEmpty() )
		b = stack.pop();
	      if ( !stack.isEmpty() )
		a = stack.pop();
	      else
		//如果一个运算符无法对应两个数字则说明表达式不规范
		{ flag = 30; break; }
	      result = a + b;
	      stack.push( result );
	    }
	  else if ( str[i] == '-' )
	    {
	      if ( !stack.isEmpty() )
		b = stack.pop();
	      if ( !stack.isEmpty() )
		a = stack.pop();
	      else
		{ flag = 30; break; }
	      result = a - b;
	      stack.push( result );
	    }
	  else if ( str[i] == '*' )
	    {
	      if ( !stack.isEmpty() )
		b = stack.pop();
	      if ( !stack.isEmpty() )
		a = stack.pop();
	      else
		{ flag = 30; break; }
	      result = a * b;
	      stack.push( result );
	    }
	  else if ( str[i] == '/' )
	    {
	      if ( !stack.isEmpty() )
		b = stack.pop();
	      if ( !stack.isEmpty() )
		a = stack.pop();
	      else
		{ flag = 30; break; }
	      //除数为零时引发异常处理
	      if ( b == 0 )
		{ flag = 10; break; }
	      result = a / b;
	      stack.push( result );
	    }
	  else if ( str[i] == '^' )
	    {
	      if ( !stack.isEmpty() )
		b = stack.pop();
	      if ( !stack.isEmpty() )
		a = stack.pop();
	      else
		{ flag = 30; break; }
	      //底数和指数同时为零时引发异常处理
	      if ( b == 0 && a == 0 )
		{ flag = 20; break; }
	      result = pow(a,b);
	      stack.push( result );
	    }
	}
      result = stack.pop();
      if ( !stack.isEmpty() ) flag = 30;
      if ( flag == 0 )
	std::cout << Str << " = " << result << std::endl;
      else if ( flag == 10 )
	std::cout << "错误：除数为零" << std::endl;
      else if ( flag == 20 )
	std::cout << "错误：指数和底数均为零" << std::endl;
      else if ( flag == 30 )
	std::cout << "错误：表达式不符合规范" << std::endl;
    }
  flag = 0;
};

#endif
